import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ArticleContentEntity, ArticleContentType } from './article-content.entity';
import { In, Like, Not, Repository } from 'typeorm';
import { ErrorEnum } from '~/constants/error-code.constant';
import { CommonStatus } from '~/common/entity/common.entity';
import {
  ArticleBindCategoryDto,
  SimpleCreateArticleContentDto,
  SimpleUpdateArticleContentDto,
} from './article-content.dto';
import { isNil } from 'lodash';
import { PagerDto } from '~/common/dto/pager.dto';
import { Pagination } from '~/helper/paginate/pagination';
import { paginate } from '~/helper/paginate';
import { standardPaginate, StandardPagination } from '~/helper/paginate';
import { ArticleContentUserReviewService } from './article-content-user-review/article-content-user-review.service';
import { ArticleContentDetail } from './article-content.model';

@Injectable()
export class ArticleContentService {
  constructor(
    @InjectRepository(ArticleContentEntity)
    private readonly articleContentRepo: Repository<ArticleContentEntity>,
    private readonly articleContentUserReviewService: ArticleContentUserReviewService
  ) {}

  async create(
    articleContent: Partial<ArticleContentEntity> & { categorieIds?: number[]; tenantId?: number }
  ): Promise<ArticleContentEntity> {
    let tenant = null;

    // if (articleContent?.tenantId) {
    //   tenant = { id: articleContent.tenantId };
    // } else {
    //   throw new BadRequestException(ErrorEnum.NO_TENANT);
    // }

    const categories = (articleContent?.categorieIds ?? []).map((id) => ({ id }));

    return await this.articleContentRepo.save({
      ...articleContent,
      tenant,
      category: {
        id: articleContent?.categorieIds[0],
      },
    });
  }

  /**
   * 简单创建文章内容
   * @param dto 简单创建DTO
   * @returns 创建的文章内容实体
   */
  async simpleCreate(dto: SimpleCreateArticleContentDto): Promise<ArticleContentEntity> {
    // 检查categoryId和code组合是否已存在
    const existingArticle = await this.articleContentRepo.findOne({
      where: {
        code: dto.code,
        category: { id: dto.categoryId },
      },
    });

    // 如果存在，则执行更新操作
    if (!isNil(existingArticle)) {
      const updateDto: SimpleUpdateArticleContentDto = {
        name: dto.name,
        rawHtml: dto.rawHtml,
        video: dto.video,
        banner: dto.banner,
        author: dto.author,
      };

      return await this.simpleUpdate(existingArticle.id, updateDto);
    }

    // 如果不存在，则创建新记录
    // 设置默认作者（如果没有提供）
    const defaultAuthor = dto?.author ?? '';

    return await this.articleContentRepo.save({
      code: dto.code,
      name: dto.name,
      rawHtml: dto.rawHtml,
      video: dto.video,
      banner: dto.banner,
      author: defaultAuthor,
      category: {
        id: dto.categoryId,
      },
      status: CommonStatus.YES,
      type: (dto?.type as ArticleContentType) ?? ArticleContentType.MEDICAL_KNOWLEDGE,
    });
  }

  /**
   * 简单更新文章内容
   * @param id 文章ID
   * @param dto 简单更新DTO
   * @returns 更新后的文章内容实体
   */
  async simpleUpdate(
    id: number,
    dto: SimpleUpdateArticleContentDto
  ): Promise<ArticleContentEntity> {
    // 检查文章是否存在
    const existingArticle = await this.articleContentRepo.findOne({
      where: { id, status: CommonStatus.YES },
    });

    if (isNil(existingArticle)) {
      throw new BadRequestException(ErrorEnum.NO_ARTICLE_CONTENT);
    }

    // 构建更新数据对象，只包含有值的字段
    const updateData: Partial<ArticleContentEntity> = {};

    if (dto.name !== undefined) {
      updateData.name = dto.name;
    }

    if (dto.rawHtml !== undefined) {
      updateData.rawHtml = dto.rawHtml;
    }

    if (dto.video !== undefined) {
      updateData.video = dto.video;
    }

    if (dto.banner !== undefined) {
      updateData.banner = dto.banner;
    }

    if (dto.author !== undefined) {
      updateData.author = dto.author;
    }

    // 执行更新
    await this.articleContentRepo.update(id, updateData);

    // 返回更新后的实体
    return await this.articleContentRepo.findOne({
      where: { id },
    });
  }

  /**
   * 通过编码查询文章内容（保留原方法以兼容）
   * @param code 文章编码
   * @returns 文章内容详情
   */
  async findByCodeAndCategory(code: string, categoryId: number): Promise<ArticleContentEntity> {
    const article = await this.articleContentRepo.findOne({
      where: { code, category: { id: categoryId } },
    });

    if (isNil(article)) {
      return null;
    }

    return article;
  }

  async findAll(): Promise<ArticleContentEntity[]> {
    return await this.articleContentRepo.find({
      select: [
        'id',
        'code',
        'name',
        'banner',
        'author',
        'type',
        'viewCount',
        'likeCount',
        'collectCount',
        'shareCount',
        'video',
        'publishTime',
        'fileName',
        'status',
        'createdAt',
        'updatedAt',
      ],
      relations: ['category'],
    });
  }

  async findCategoryIdsByArticleId(articleId: number): Promise<number[]> {
    const result = await this.articleContentRepo
      .createQueryBuilder('content') // 设置别名为 content（更清晰）
      .leftJoin('content.categories', 'category') // 关联 ManyToMany 字段
      .select('category.id', 'categoryId') // 只要 category 的 ID
      .where('content.id = :articleId', { articleId })
      .getRawMany();

    // 提取分类 ID 数组
    return result.map((row) => row.categoryId);
  }

  async findOne(id: number, userId?: number): Promise<Partial<ArticleContentDetail>> {
    const article: ArticleContentDetail = await this.articleContentRepo.findOne({
      where: { id, status: CommonStatus.YES },
      relations: ['category'],
    });

    if (isNil(userId)) {
      article.hasReview = false;
    } else {
      const contentUserReview = await this.articleContentUserReviewService.findOneByUserAndArticle(
        id,
        userId
      );
      article.hasReview = !isNil(contentUserReview);
    }

    article.categoryId = article.category?.id ?? null;
    delete article.category;

    await this.addViewCount(id);

    return article;
  }

  async findRecommend(tenantId: number): Promise<ArticleContentEntity[]> {
    if (!tenantId) {
      throw new BadRequestException(ErrorEnum.NO_TENANT);
    }

    return await this.articleContentRepo.find({
      select: [
        'id',
        'name',
        'banner',
        'author',
        'viewCount',
        'likeCount',
        'shareCount',
        'collectCount',
        'createdAt',
      ],
      where: { tenant: { id: tenantId }, status: CommonStatus.YES },
      order: { createdAt: 'DESC' },
      relations: ['categories'],
      take: 10,
    });
  }

  async findListByCategoryId({
    page,
    pageSize,
    categoryId,
    tenantId,
  }: PagerDto & { categoryId: number; tenantId: number }): Promise<
    Pagination<ArticleContentEntity>
  > {
    const queryBuilder = await this.articleContentRepo
      .createQueryBuilder('ah_article_content')
      .leftJoin('ah_article_content.categories', 'category')
      .select([
        'ah_article_content.id',
        'ah_article_content.name',
        'ah_article_content.banner',
        'ah_article_content.author',
        'ah_article_content.viewCount',
        'ah_article_content.likeCount',
        'ah_article_content.shareCount',
        'ah_article_content.collectCount',
        'ah_article_content.createdAt',
      ])
      .where({
        tenant: { id: tenantId },
        status: CommonStatus.YES,
      })
      .andWhere('category.id = :categoryId', { categoryId })
      .orderBy('ah_article_content.createdAt', 'DESC');

    return paginate<ArticleContentEntity>(queryBuilder, {
      page,
      pageSize,
    });
  }

  async findByName(name: string, tenantId: number): Promise<ArticleContentEntity[]> {
    if (!tenantId) {
      throw new BadRequestException(ErrorEnum.NO_TENANT);
    }

    return await this.articleContentRepo.find({
      select: [
        'id',
        'name',
        'banner',
        'author',
        'viewCount',
        'likeCount',
        'shareCount',
        'collectCount',
      ],
      where: {
        name: Like(`%${name}%`),
      },
      order: { createdAt: 'DESC' },
    });
  }

  async update(id: number, articleContent: Partial<ArticleContentEntity>): Promise<void> {
    await this.articleContentRepo.update(id, articleContent);
  }

  async remove(id: number): Promise<void> {
    // 软删除：将状态设置为失效状态而不是直接删除记录
    await this.articleContentRepo.update(id, { status: CommonStatus.NO });
  }

  async addLikeCount(id: number): Promise<void> {
    await this.articleContentRepo.increment({ id }, 'likeCount', 1);
  }

  async deleteLikeCount(id: number): Promise<void> {
    await this.articleContentRepo.decrement({ id }, 'likeCount', 1);
  }

  async addViewCount(id: number): Promise<void> {
    await this.articleContentRepo.increment({ id }, 'viewCount', 1);
  }

  async deleteViewCount(id: number): Promise<void> {
    await this.articleContentRepo.decrement({ id }, 'viewCount', 1);
  }

  async addShareCount(id: number): Promise<void> {
    await this.articleContentRepo.increment({ id }, 'shareCount', 1);
  }

  async addCollectCount(id: number): Promise<void> {
    await this.articleContentRepo.increment({ id }, 'collectCount', 1);
  }

  async deleteCollectCount(id: number): Promise<void> {
    await this.articleContentRepo.decrement({ id }, 'collectCount', 1);
  }

  async bindCategory(dto: ArticleBindCategoryDto): Promise<void> {
    // 判断文章内容是否存在
    const articleContent = await this.findOne(dto.articleId);

    if (isNil(articleContent)) {
      throw new BadRequestException(ErrorEnum.NO_ARTICLE_CONTENT);
    }

    // 绑定分类
    await this.articleContentRepo
      .createQueryBuilder()
      .relation(ArticleContentEntity, 'categories')
      .of(articleContent)
      .add(dto.categorieIds);
  }

  async findByCategoryId(categoryId?: number): Promise<ArticleContentEntity[]> {
    return await this.articleContentRepo.find({
      where: {
        ...(categoryId ? { category: { id: categoryId } } : {}),
        status: CommonStatus.YES,
      },
    });
  }

  /**
   * 根据文章类型和分类ID查找文章内容
   * @param type 文章内容类型
   * @param categoryId 分类ID
   * @returns
   */
  async findByTypeAndCategoryId(
    type: ArticleContentType,
    categoryId?: number
  ): Promise<ArticleContentEntity[]> {
    return await this.articleContentRepo.find({
      where: {
        type,
        ...(categoryId ? { category: { id: categoryId } } : {}),
        status: CommonStatus.YES,
      },
    });
  }

  /**
   * 首页推荐列表
   * @returns
   */
  async findTopRecommendByScience(categoryId?: number): Promise<ArticleContentEntity[]> {
    const topRecommendList = await this.articleContentRepo.find({
      where: {
        ...(categoryId ? { category: { id: categoryId } } : {}),
        status: CommonStatus.YES,
        type: ArticleContentType.SCIENCE_KNOWLEDGE,
      },
      select: [
        'id',
        'name',
        'code',
        'banner',
        'author',
        'viewCount',
        'likeCount',
        'shareCount',
        'collectCount',
        'publishTime',
      ],
      order: {
        viewCount: 'DESC',
      },
      take: 10,
    });

    const randomRecommendList = await this.articleContentRepo
      .createQueryBuilder('article')
      .where({
        ...(categoryId ? { category: { id: categoryId } } : {}),
        status: CommonStatus.YES,
        type: ArticleContentType.SCIENCE_KNOWLEDGE,
        id: Not(In(topRecommendList.map((item) => item.id))),
      })
      .select([
        'article.id',
        'article.name',
        'article.code',
        'article.banner',
        'article.author',
        'article.viewCount',
        'article.likeCount',
        'article.shareCount',
        'article.collectCount',
        'article.publishTime',
      ])
      .orderBy('RAND()') // 使用随机排序
      .take(10)
      .getMany();

    return [...topRecommendList, ...randomRecommendList];
  }

  /**
   * 查找科普知识类型的文章分页数据
   * @param options 分页参数
   * @param categoryId 可选的分类ID
   * @param name 可选的文章名称（模糊查询）
   * @param code 可选的编码（模糊查询）
   * @returns 科普知识文章的分页结果
   */
  async findScienceKnowledgePage({
    page,
    pageSize,
    categoryId,
    name,
    code,
  }: PagerDto & { categoryId?: number; name?: string; code?: string }): Promise<
    StandardPagination<ArticleContentEntity>
  > {
    const queryBuilder = this.articleContentRepo
      .createQueryBuilder('content')
      .leftJoinAndSelect('content.category', 'category')
      .select([
        'content.id',
        'content.name',
        'content.code',
        'content.banner',
        'content.video',
        'content.author',
        'content.viewCount',
        'content.likeCount',
        'content.collectCount',
        'content.shareCount',
        'content.status',
        'content.createdAt',
        'category.id',
      ])
      .where('content.type = :type', { type: ArticleContentType.SCIENCE_KNOWLEDGE })
      .andWhere('content.status = :status', { status: CommonStatus.YES })
      .orderBy('content.createdAt', 'DESC');

    // 根据分类ID筛选
    if (categoryId) {
      queryBuilder.andWhere('content.category.id = :categoryId', { categoryId });
    }

    // 根据文章名称模糊查询
    if (name) {
      queryBuilder.andWhere('content.name LIKE :name', { name: `%${name}%` });
    }

    // 根据编码模糊查询
    if (code) {
      queryBuilder.andWhere('content.code LIKE :code', { code: `%${code}%` });
    }

    return standardPaginate(queryBuilder, { page, pageSize });
  }
}
